#include <output_stream.h>


Output_Stream::Output_Stream(const char* url)
{
    this->m_url = url;

    avformat_alloc_output_context2(&m_format_context, NULL, "rtsp", url);
    if (!m_format_context) {
          fprintf(stderr, "Could not create output context\n");   
          m_open_success = false;
          return ;     
    }
    m_open_success = true;

    gettimeofday(&m_start_time, NULL);
    gettimeofday(&m_last_time, NULL);
}

bool Output_Stream::add_stream(AVCodecParameters* parameters, AVRational& time_base)
{
    
    if(m_open_success){
        if(parameters->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            m_video_stream = avformat_new_stream(m_format_context, NULL);

            m_video_stream->codecpar = parameters;
            m_video_stream->time_base = time_base;
        }else if(parameters->codec_type == AVMEDIA_TYPE_AUDIO) {
            m_audio_stream = avformat_new_stream(m_format_context, NULL);

            m_audio_stream->codecpar = parameters;
            m_audio_stream->time_base = time_base;
        }
    }
    return true;
}

int Output_Stream::write_audio_frame(AVPacket* packet)
{
    int ret = 0;
    if(m_open_success && !m_write_header) {
        m_write_header =  true;
        if (avformat_write_header(m_format_context, NULL) < 0) {
            fprintf(stderr, "Error occurred when writing header\n");            
            return -1;
        }
    }        

    if(m_audio_last_dts == 0) {
        m_audio_last_dts = packet->dts;
    }else {
        if(packet->dts<=m_audio_last_dts) {
            fprintf(stderr, "Error current dts :%lld,last dts:%ld packet->index:%d\n",packet->dts,m_audio_last_dts,packet->stream_index);
            packet->dts = m_audio_last_dts+1;            
        }
        m_audio_last_dts = packet->dts ;       
    }

    if( m_audio_last_pts == 0) {
         m_audio_last_pts = packet->pts;
    }else {
        if(packet->pts<m_audio_last_dts) {
            fprintf(stderr, "Error current pts :%lld,last dts:%ld \n",packet->pts,m_audio_last_pts);
           packet->pts = packet->dts; 
        }
        m_audio_last_pts = packet->pts ;
    }
    packet->stream_index = 1;
    if (ret = av_interleaved_write_frame(m_format_context, packet) < 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));

        fprintf(stderr, "Error while writing audio packet:%s \n",errbuf);     
        return -1;      
    }
    m_audio_frame_out_cnt++;
    return 0;
}
int Output_Stream::write_video_frame(AVPacket* packet)
{
    int ret = 0;
    if(m_open_success && !m_write_header) {
        m_write_header =  true;
        if (avformat_write_header(m_format_context, NULL) < 0) {
            fprintf(stderr, "Error occurred when writing header\n");            
            return -1;
        }
    }
    if(!m_write_idr) {
        if(packet->flags == 1) {
            m_write_idr = true;
        }else {
            //skip this packet
            return 0;
        }
    }
   
    if( m_video_last_pts == 0) {
         m_video_last_pts = packet->pts;
    }else {
        if(packet->pts<m_video_last_dts) {
            fprintf(stderr, "Error current pts :%lld,last dts:%ld \n",packet->pts,m_video_last_pts);
           packet->pts = packet->dts; 
        }
        m_video_last_pts = packet->pts ;
    }

    packet->stream_index = 0;

    if (ret = av_interleaved_write_frame(m_format_context, packet) < 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));

        fprintf(stderr, "Error while writing video packet:%s \n",errbuf);     
        return -1;      
    }
    m_video_frame_out_cnt++;
    //statistic_info(0);
    return 0;
}
Output_Stream::~Output_Stream()
{
    if(m_format_context) {
        av_write_trailer(m_format_context);
    }
}

void Output_Stream::statistic_info(int force)
{
     struct timeval curr_time;
     int64_t duration;
     double audio_fps,video_fps;

     gettimeofday(&curr_time, NULL);
     if (force ||
         (get_time_duration(&curr_time, &m_last_time) > (1 * 1000 * 1000))) {
            duration = get_time_duration(&curr_time, &m_start_time);
            video_fps      = (double)m_video_frame_out_cnt /
               ((double)duration / (1 * 1000 * 1000));
            audio_fps      = (double)m_audio_frame_out_cnt /
               ((double)duration / (1 * 1000 * 1000));
            av_log(NULL, AV_LOG_INFO, "\n frame %5d, video_fps=%3.1f audio_fps=%3.1f", m_video_frame_out_cnt, video_fps,audio_fps);           
            m_last_time = curr_time;
     }
}